_fp = @fopen($file, 'rb'))) return false; $this->_size = filesize($file); return $this->_getCD(); } function close() { @fclose($this->_fp); } // reset the internal array pointer on the CD function rewind() { reset($this->_cd); } // return the next entry function getFileNew($content = false) { list(, $f) = each($this->_cd); if(!$f) return false; $f = $this->_normalize($f); if($content) $f['content'] = $this->extractFile($f); return $f; } function getFile($name = '') { if($name == '') { return $this->getFileNew(true); } else { for($i = 0, $c = count($this->_cd); $i < $c; $i++) { $tmp = $this->_normalize($this->_cd[$i]); if($tmp['name'] == $name); $tmp['content'] = $this->extractFile($name); return $tmp; } } return false; } // return all entries function getFileList() { $list = array(); for($i = 0, $c = count($this->_cd); $i < $c; $i++) { $tmp = $this->_normalize($this->_cd[$i]); $list[] = $tmp['name']; } return $list; } // return zip file info function getInfo() { return array ( 'entries' => $this->_ecdr['disk_cdr_entries_num'], 'comment' => $this->_ecdr['comment'] ); } // Extract file content to $target. // $path can be file path or array from getFile(). // If $target is path to directory, create a file named after the file and write to it // If $target is path to file, open/create file and write to it // If $target is false, return content // Return false if fails. function extractFile($path, $target = false) { $path = is_array($path) ? $path['path'] : $path; if(!isset($this->_tbl[$path])) return false; $file = $this->_cd[$this->_tbl[$path]]; // if $file is_dir, create dir in $target if it's a dir if($file['is_dir'] && is_dir($target)) { return mkdir($target . '/' . $file['path']); } // read past local file header to the file content $lfh_offset = $file['rel_offset']; if(fseek($this->_fp, $lfh_offset, SEEK_SET) !== 0) return false; $lfh_data = fread($this->_fp, 30); if(strlen($lfh_data) != 30) return false; $lfh = unpack('Vheader_sig/Sversion_extract/Sgen_purpose/Scompression_method' . '/Slast_mod_time/Slast_mod_date/Vcrc_32/Vcompressed_size' . '/Vuncompressed_size/Sfilename_len/Sextra_field_len', $lfh_data); $offset = $lfh['filename_len'] + $lfh['extra_field_len']; if(fseek($this->_fp, $offset, SEEK_CUR) !== 0) return false; $content = $lfh['compressed_size'] ? fread($this->_fp, $lfh['compressed_size']) : ''; if($lfh['compression_method'] == 8 && strlen($content)) $content = gzinflate($content); if(!$target) return $content; if(is_resource($target)) return fwrite($target, $content); $fp = null; if(is_dir($target)) { $fp = is_dir($target . '/' . dirname($file['path'])) ? fopen($target . '/' . $file['path'], 'wb') : fopen($target . '/' . $file['filename'], 'wb'); } else { $fp = fopen($target, 'wb'); } if($fp) { fwrite($fp, $content); fclose($fp); return true; } return false; } // translate CD entry to normalized info array function _normalize($entry) { return array ( 'path' => $entry['path'], 'name' => $entry['filename'], 'size' => $entry['uncompressed_size'], 'csize'=> $entry['compressed_size'], 'is_dir' => $entry['is_dir'], 'comment'=> $entry['comment'] ); } // read in Central Directory // return true/false function _getCD() { if(fseek($this->_fp, -22, SEEK_END) !== 0) return false; $ecdr_data = fread($this->_fp, 22); if(strlen($ecdr_data) !== 22) return false; $ecdr = unpack('Vcdr_sig/vdisk_num/vcdr_disk_num/vdisk_cdr_entries_num' . '/vcdr_entries_num/Vcdr_size/Vstart_disk_cdr_offset' . '/vcomment_len', $ecdr_data); if($ecdr['cdr_sig'] === 0x06054b50) { $ecdr['comment'] = ''; } else { $seek_pos = min(65558, $this->_size); if(fseek($this->_fp, -$seek_pos, SEEK_END) !== 0) return false; $ecdr_max = fread($this->_fp, 65558); if(false === ($ecdr_offset = strpos($ecdr_max, "\x50\x4b\x05\x06"))) return false; $ecdr_data = substr($ecdr_max, $ecdr_offset, 22); $ecdr = unpack('Vcdr_sig/vdisk_num/vcdr_disk_num' . '/vdisk_cdr_entries_num/vcdr_entries_num/Vcdr_size' . '/Vstart_disk_cdr_offset/vcomment_len', $ecdr_data); $ecdr['comment'] = substr($ecdr_max, $ecdr_offset + 22, $ecdr['comment_len']); } $this->_ecdr = $ecdr; // got ECDR, get CD if(fseek($this->_fp, $ecdr['start_disk_cdr_offset'], SEEK_SET) !== 0) return false; for($i = 0, $c = $ecdr['disk_cdr_entries_num']; $i < $c; $i++) { $fh_data = fread($this->_fp, 46); if(strlen($fh_data) != 46 || feof($this->_fp)) return false; $fh = unpack('Vcfh_sig/Cversion_made_by_lower/Cversion_made_by_upper' . '/vv_extract/vgen_flag/vcomppression_method/vmod_time' . '/vmode_date/Ncrc32/Vcompressed_size/Vuncompressed_size' . '/vfilename_len/vxtra_len/vcomment_len/vdisk_num_start' . '/vinternal_attrib/Vexternal_attrib/Vrel_offset', $fh_data); if(!is_array($fh) || $fh['cfh_sig'] != 33639248) return false; $len = $fh['filename_len'] + $fh['xtra_len'] + $fh['comment_len']; $data = fread($this->_fp, $len); $fh['path'] = substr($data, 0, $fh['filename_len']); $fh['name'] = $fh['path']; $fh['filename'] = basename($fh['path']); $fh['extra'] = substr($data, $fh['filename_len'], $fh['xtra_len']); $fh['comment'] = substr($data, $fh['filename_len'] + $fh['xtra_len'], $fh['comment_len']); $fh['is_dir'] = $fh['version_made_by_upper'] == 0 && ($fh['external_attrib'] & 16); $this->_tbl["{$fh['path']}"] = count($this->_cd); $this->_cd[] = $fh; } return true; } function _getEntry($lfh_offset) { if(fseek($this->_fp, $lfh_offset, SEEK_SET) !== 0) return false; $lfh = unpack('Vheader_sig/Sversion_extract/Sgen_purpose/Scompression_method/Slast_mod_time/Slast_mod_date/Vcrc_32/Vcompressed_size/Vuncompressed_size/Sfile_name_length/Sextra_field_length', fread($this->_fp, 30)); $lfh['name'] = $lfh['file_name_length'] ? fread($this->_fp, $lfh['file_name_length']) : ''; $lfh['extra_field'] = $lfh['extra_field_length'] ? fread($this->_fp, $lfh['extra_field_length']) : ''; if($lfh['compression_method'] == 8) $file_content = $lfh['compressed_size'] ? @gzinflate(fread($this->_fp, $lfh['compressed_size'])) : ''; elseif($lfh['compression_method'] == 0) $file_content = $lfh['compressed_size'] ? fread($this->_fp, $lfh['compressed_size']) : ''; else return false; $ldd = $lfh['gen_purpose'] & 8 ? unpack('Vcrc_32/Vcompressed_size/Vuncompressed_size', fread($this->_fp, 12)) : ''; return array('name' => $lfh['name'], 'size' => $lfh['uncompressed_size'], 'content' => &$file_content); } } ?>